package fi.iki.joker.mobilogger;

import java.util.LinkedList;
import java.util.Map;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TableLayout;
import fi.iki.joker.mobilogger.blogs.BlogConfigConstants;
import fi.iki.joker.mobilogger.blogs.BlogInterface;
import fi.iki.joker.mobilogger.blogs.BlogInterfaceFactory;
import fi.iki.joker.mobilogger.db.BlogConfigBean;
import fi.iki.joker.mobilogger.db.DBUtil;
import fi.iki.joker.mobilogger.util.AlertUtil;

public class BlogConfigEditor extends Activity implements 
		AdapterView.OnItemSelectedListener,
		View.OnClickListener {
	
	BlogInterface bi;
	BlogConfigBean myBlogConfig = null;
	//this variable is used in edit mode to remember the old type
	//of the configuration in case user changes the blog config
	//type to another type. It's used in attribute loading from DB.
	private int mOldConfigType = -1;
	private final String TAG = "BlogConfigEditor";
	private static final int STATE_INSERT = 0;
	private static final int STATE_EDIT = 1;
	private static final int STATE_DELETE = 2;
	private int mState = 0;
	private Uri mURI = null;
	/**
	 * The dynamically added table rows are ID'd starting from this number onwards
	 */
	private final int DYNAMIC_FIELD_ID_LIMIT = 600;
	public void onNothingSelected(AdapterView arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected void onCreate(Bundle icicle) {
		// TODO Auto-generated method stub
		super.onCreate(icicle);
		setContentView(R.layout.blogconfigeditor);
		final Intent intent = getIntent();
		if(intent.getAction().equals(Intent.ACTION_INSERT)) {
			mState = STATE_INSERT;
			myBlogConfig = new BlogConfigBean();
			myBlogConfig.setPostmethod(
				BlogConfigConstants.getInterfaceNumberByType(BlogConfigConstants.BlogInterfaceType.BLOGGER));
			myBlogConfig.setPostConfig("");
		} else if(intent.getAction().equals(Intent.ACTION_EDIT)) {
			mState = STATE_EDIT;
			mURI = intent.getData();
        	int configid = -1;
        	String id = mURI.getPath();
        	String temp = null;
        	if(id != null) {
        		try {
        			temp = id.substring(id.lastIndexOf('/')+1);
        			configid = Integer.parseInt(temp);
        		} catch (NumberFormatException ne) {
        			Log.e(TAG, "Unable to parse the Intent path id ("+temp+") into an integer!");
        		}
        	}
        	if(configid > 0) {
        		DBUtil conn = new DBUtil();
    	        Log.d(TAG, "DB ready, fetching config memo");
    	        myBlogConfig = conn.getBlogConfigById(this,configid);
        	}
		} else if(intent.getAction().equals(Intent.ACTION_DELETE)) {
			mState = STATE_DELETE;
		}
		
		//Say that no column can be used to claim extra space for oversized colums
		TableLayout myLayout = (TableLayout)findViewById(R.id.configtablelayout);
		myLayout.setColumnStretchable(1, false);
		//create spinner where user can select the config type to create
		Spinner blogtypes = (Spinner) findViewById(R.id.blogtypespinner);
		LinkedList<String> configs = BlogConfigConstants.typeConstantTitles();
		Object res = new ArrayAdapter(this,android.R.layout.simple_spinner_item,configs);
		ArrayAdapter<CharSequence> adapter = (ArrayAdapter<CharSequence>)res;
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		blogtypes.setAdapter(adapter);
		blogtypes.setOnItemSelectedListener(this);
		//Create the save button
		Button saveButton = (Button) findViewById(R.id.blogconfig_save_button);
		saveButton.setOnClickListener(this);
		if(mState == STATE_EDIT) {
			//remember which type of config this was previously
			mOldConfigType = myBlogConfig.getPostmethod();
			EditText blogname = (EditText)findViewById(R.id.configtitle);
			EditText username = (EditText)findViewById(R.id.usernameconfig);
			EditText password = (EditText)findViewById(R.id.passwordconfig);
			blogname.setText(myBlogConfig.getBlogname());
			username.setText(myBlogConfig.getUsername());
			password.setText(myBlogConfig.getPassword());
			blogtypes.setSelection(myBlogConfig.getPostmethod()-1);
			createConfigDependentFields(myBlogConfig);
		} else if(mState == STATE_INSERT) {
			//Everything should just be empty here if we create a new config.
			createConfigDependentFields(myBlogConfig);
		}
	}

	public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) {
		removeConfigDependentFields();
		//the field numbering in the Linkedlist (arrayadapter) starts from 0, 
		//but the blog configuration numbering starts from 1. Thus +1.
		if(mState == STATE_INSERT) {
			myBlogConfig.setPostmethod(arg2+1);
			createConfigDependentFields(myBlogConfig);
		} else if(mState == STATE_EDIT && (arg2+1 == mOldConfigType)) {
			//user has changed to a blog config type for which we have already
			//some saved settings
			myBlogConfig.setPostmethod(arg2+1);
			createConfigDependentFields(myBlogConfig);
		} else if(mState == STATE_EDIT) {
			//user edits a blog config and changes to a new type for which we
			//don't have any settings saved.
			myBlogConfig.setPostmethod(arg2+1);
			createConfigDependentFields(myBlogConfig);
		}
	}
	
	/**
	 * Handles the clicks to the "save" button. Other clickables need to register different listeners.
	 */

	public void onClick(View arg0) {
		EditText blogname = (EditText)findViewById(R.id.configtitle);
		EditText username = (EditText)findViewById(R.id.usernameconfig);
		EditText password = (EditText)findViewById(R.id.passwordconfig);
		if(password == null || password.getText() == null) {
			Log.d(TAG,"password editor view is null when trying to read!");
			return;
		}
		if (username == null || username.getText() == null) {
			Log.d(TAG,"username editor view is null when trying to read!");
			return;
		}
		if (blogname == null || blogname.getText() == null) {
			Log.d(TAG,"blogname editor view is null when trying to read!");
			return;
		}
		String blognameStr = blogname.getText().toString();
		String usernameStr = username.getText().toString();
		String passwordStr = password.getText().toString();
		
		//Read blog's name
		if(blognameStr.length() < 1) {
			AlertUtil.showAlert(this,"Empty title","You need to have a name for this blog.");
			return;
		} 	
		if(usernameStr.length() < 1) {
			AlertUtil.showAlert(this,"Empty username","You need to have a username for this blog.");
			return;
		} 
		if(passwordStr.length() < 1) {
			AlertUtil.showAlert(this,"Empty password","You need to have a password for this blog.");
			return;
		} 
		myBlogConfig.setBlogname(blogname.getText().toString());
		myBlogConfig.setUsername(username.getText().toString());
		myBlogConfig.setPassword(password.getText().toString());
		// read blogtype specific configuration data 
		if(bi != null) {
			CharSequence cs = bi.getConfigEditorData();
			myBlogConfig.setPostConfig(cs);
		} else {
			AlertUtil.showAlert(this,"nag", "nag");
		}
		//remember that the post method (i.e. which type of blog this is)
		//is already set by the OnItemSelected callback.
		DBUtil conn = new DBUtil();
		if(conn != null) {
			if(mState == STATE_INSERT) {
				conn.insert(this,myBlogConfig);
				Log.d(TAG,"Blog Config saved to database.");
			} else if(mState == STATE_EDIT) {
				conn.update(this,myBlogConfig);
				Log.d(TAG,"Blog Config with id="+myBlogConfig.getId()+"updated in database.");
			}
			
			this.finish();
		} else {
			AlertUtil.showAlert(this,"ERROR","Unable to save configuration. Check your device memory.");
			Log.e(TAG, "ERROR saving blog config to DB due to DBUtil error.");
		}
		
	}

	/**
	 * This calls into the class that represents the current blog interface thats being edited.
	 * It creates, with the help of this class, the GUI widgets of the editor which are specific to
	 * this particular type of blog configuration. The views created should have DYNAMIC_FIELD_ID_LIMIT 
	 * or larger number as their id.
	 * 
	 * @param configNum
	 * @param populateFromID
	 */
	
	private void createConfigDependentFields(BlogConfigBean bcb) {
		TableLayout table = (TableLayout)findViewById(R.id.configtablelayout);
    	//Call into the blog interface and have it create the proper GUI for 
		//It's configuration.
		BlogConfigConstants.BlogInterfaceType blogtype = BlogConfigConstants.getInterfaceTypeByNumber(bcb.getPostmethod());
		bi = BlogInterfaceFactory.getInstance(blogtype);
		bi.setInstanceConfig(bcb.getPostConfig());
		if(bi != null) {
			bi.createConfigEditorRows(this, table, this, DYNAMIC_FIELD_ID_LIMIT, bcb.getId());
		}
    }
	
	/**
	 * This method is used to clean the config-specific GUI widgets. Unlike in the creation, this method just checks if the
	 * Views are identified with ID larger than DYNAMIC_FIELD_ID_LIMIT. If they are, they are config-specific and removed.
	 */
	
	private void removeConfigDependentFields() {
		TableLayout table = (TableLayout)findViewById(R.id.configtablelayout);
		int childs = table.getChildCount();
		Log.d(TAG,"Num of childs: "+childs);
		for(int i = childs-1; i>=0; i--) {
			View inspectMe = table.getChildAt(i);
			int id = -1;
			String name = null; 
			if(inspectMe != null) {
				id = inspectMe.getId();
				name = inspectMe.toString();
			} else {
				Log.d(TAG,"Config row view was null; Object at : "+i);
			}
			Log.d(TAG,"Found view with id:"+id+", with name:"+name);
			if(id >= DYNAMIC_FIELD_ID_LIMIT) {
				table.removeView(inspectMe);
			}
		}
	}
	
	/**
	 * The Edittext that holds the Title of this configuration setting
	 * @author joker@iki.fi
	 *
	 */

	public static class ConfigTitleText extends EditText {
        private Rect mRect;
        private Paint mPaint;

        // we need this constructor for ViewInflate
        public ConfigTitleText(Context context, AttributeSet attrs) {
            super(context, attrs);

            mRect = new Rect();
            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(0xFF0000FF);
        }

        @Override
        protected void onDraw(Canvas canvas) {

            int count = getLineCount();
            Rect r = mRect;
            Paint paint = mPaint;

            for (int i = 0; i < count; i++) {
                int baseline = getLineBounds(i, r);

                canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1,
                                paint);
            }

            super.onDraw(canvas);
        }
        
    }
	
	/**
	 * The edittext that holds the username of this configuration.
	 * @author juhak
	 *
	 */
	
	public static class UsernameText extends EditText {
        private Rect mRect;
        private Paint mPaint;

        // we need this constructor for ViewInflate
        public UsernameText(Context context, AttributeSet attrs) {
            super(context, attrs);

            mRect = new Rect();
            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(0xFF0000FF);
        }

        @Override
        protected void onDraw(Canvas canvas) {

            int count = getLineCount();
            Rect r = mRect;
            Paint paint = mPaint;

            for (int i = 0; i < count; i++) {
                int baseline = getLineBounds(i, r);

                canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1,
                                paint);
            }

            super.onDraw(canvas);
        }
        
    }
	
	/**
	 * The edittext that holds the password for this configuration.
	 * @author juhak
	 */
	
	public static class PasswordText extends EditText {
        private Rect mRect;
        private Paint mPaint;

        // we need this constructor for ViewInflate
        public PasswordText(Context context, AttributeSet attrs) {
            super(context, attrs);

            mRect = new Rect();
            mPaint = new Paint();
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(0xFF0000FF);
        }

        @Override
        protected void onDraw(Canvas canvas) {

            int count = getLineCount();
            Rect r = mRect;
            Paint paint = mPaint;

            for (int i = 0; i < count; i++) {
                int baseline = getLineBounds(i, r);

                canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1,
                                paint);
            }

            super.onDraw(canvas);
        }
        
    }
}
